unit frmMain;

{$I SQLiteToolReg.inc}

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, StdCtrls, Menus, ActnList,
  RzButton, ExtCtrls,
  RzPanel, ImgList, RzTabs, ComCtrls, siComp, SQLiteUtils, 
  frmTableStruct, frmIndexInfo,
  DBCtrls, StrUtils, frmEditBlob, SynEdit, SynEditHighlighter,
  SynHighlighterSQL, SynEditActions, SynFindDlg, SynEditStrRes,
  AppEvnts, RaDBOLE, frmOptions, SQLiteConfig, RzStatus, frmAbout, SQLitePages,
  SynCompletionProposal, OleCtrls, ShellAPI,cxGridCustomView,
  SynUniHighlighter, frmHotKey, frmDTS, frmInputPwd, frmChangePwd, frmLibMgr,
  frmUnRegHint, RaGSQLite;

type
  TFormMain = class(TForm)
    sdSave:              TSaveDialog;
    mmMain:              TMainMenu;
    actLst:              TActionList;
    imgLst:              TImageList;
    tbMain:              TRzToolbar;
    BtnNew:              TRzToolButton;
    BtnOpen:             TRzToolButton;
    BtnDelete:           TRzToolButton;
    miDB:                TMenuItem;
    actNew:              TAction;
    actOpen:             TAction;
    actClose:            TAction;
    miNewDB:             TMenuItem;
    miOpenDB:            TMenuItem;
    miCloseDB:           TMenuItem;
    miEdit:              TMenuItem;
    actNewTable:         TAction;
    actModifyTable:      TAction;
    actDeleteTable:      TAction;
    actNewIndex:         TAction;
    actDeleteIndex:      TAction;
    RzSpacer1:           TRzSpacer;
    btnNewTable:         TRzToolButton;
    btnModifyTable:      TRzToolButton;
    btnDEleteTable:      TRzToolButton;
    btnNewIndex:         TRzToolButton;
    btnDeleteIndex:      TRzToolButton;
    RzSpacer2:           TRzSpacer;
    CreateTable1:        TMenuItem;
    ModifyTable1:        TMenuItem;
    DeleteTable1:        TMenuItem;
    N1:                  TMenuItem;
    CreateIndex1:        TMenuItem;
    DeleteIndex1:        TMenuItem;
    ppMain:              TRzPageControl;
    actBackup:           TAction;
    BackupDatabase1:     TMenuItem;
    N2:                  TMenuItem;
    tvDB:                TTreeView;
    Splitter1:           TSplitter;
    siLang:              TsiLang;
    odOpen:              TOpenDialog;
    miOptions:           TMenuItem;
    miLang:              TMenuItem;
    miEnglish:           TMenuItem;
    miChinese:           TMenuItem;
    DSQry:               TDataSource;
    N3:                  TMenuItem;
    miExit:              TMenuItem;
    DSTbl:               TDataSource;
    SQL:                 TSynSQLSyn;
    actExec:             TAction;
    actSave:             TAction;
    miSQL:               TMenuItem;
    ExecuteSQL1:         TMenuItem;
    SaveScript1:         TMenuItem;
    RzSpacer3:           TRzSpacer;
    sdSQL:               TSaveDialog;
    aSynFind1:           TaSynFind;
    aSynFindNext1:       TaSynFindNext;
    aSynReplace1:        TaSynReplace;
    aSynUndo1:           TaSynUndo;
    aSynRedo1:           TaSynRedo;
    aSynCut1:            TaSynCut;
    aSynCopy1:           TaSynCopy;
    aSynPaste1:          TaSynPaste;
    aSynSelectAll1:      TaSynSelectAll;
    Edit1:               TMenuItem;
    aSynUndo11:          TMenuItem;
    aSynRedo11:          TMenuItem;
    N4:                  TMenuItem;
    aSynCut11:           TMenuItem;
    aSynCopy11:          TMenuItem;
    aSynPaste11:         TMenuItem;
    aSynDelete1:         TAction;
    aSynDelete11:        TMenuItem;
    N5:                  TMenuItem;
    aSynSelectAll11:     TMenuItem;
    Search1:             TMenuItem;
    aSynFind11:          TMenuItem;
    aSynFindNext11:      TMenuItem;
    N6:                  TMenuItem;
    aSynReplace11:       TMenuItem;
    tbSQL:               TRzToolbar;
    RzToolButton11:      TRzToolButton;
    RzToolButton12:      TRzToolButton;
    RzToolButton13:      TRzToolButton;
    RzSpacer7:           TRzSpacer;
    RzToolButton19:      TRzToolButton;
    RzToolButton20:      TRzToolButton;
    BtnUndo:             TRzToolButton;
    BtnRedo:             TRzToolButton;
    BtnCut:              TRzToolButton;
    BtnCopy:             TRzToolButton;
    BtnPaste:            TRzToolButton;
    BtnFind:             TRzToolButton;
    BtnReplace:          TRzToolButton;
    BtnFindNext:         TRzToolButton;
    RzSpacer4:           TRzSpacer;
    RzSpacer5:           TRzSpacer;
    RzSpacer6:           TRzSpacer;
    RzSpacer8:           TRzSpacer;
    BtnUtilities:        TRzToolButton;
    BtnExit:             TRzToolButton;
    RzSpacer9:           TRzSpacer;
    RzSpacer10:          TRzSpacer;
    BtnUtilities1:       TRzToolButton;
    RzSpacer11:          TRzSpacer;
    BtnExit1:            TRzToolButton;
    actOptions:          TAction;
    actExit:             TAction;
    Help1:               TMenuItem;
    actAbout:            TAction;
    About1:              TMenuItem;
    ApplicationEvents1:  TApplicationEvents;
    Blob:                TRaDBOLE;
    pmEdit:              TPopupMenu;
    Undo1:               TMenuItem;
    Redo1:               TMenuItem;
    N7:                  TMenuItem;
    Cut1:                TMenuItem;
    Copy1:               TMenuItem;
    Paste1:              TMenuItem;
    Delete1:             TMenuItem;
    N8:                  TMenuItem;
    SelectAll1:          TMenuItem;
    sbMain:              TRzStatusBar;
    spStat:              TRzStatusPane;
    spPOS:               TRzStatusPane;
    Options1:            TMenuItem;
    pmLV1:               TPopupMenu;
    pmLV2:               TPopupMenu;
    actOpenTable:        TAction;
    actSQLWindow:        TAction;
    actOpenStructure:    TAction;
    actDeleteObj:        TAction;
    OpenTable1:          TMenuItem;
    OpenTableStructure1: TMenuItem;
    actOutScript:        TAction;
    ModifyTable2:        TMenuItem;
    N9:                  TMenuItem;
    OpenSQLWindow1:      TMenuItem;
    OutputScript1:       TMenuItem;
    N10:                 TMenuItem;
    DeleteTable2:        TMenuItem;
    OutputScript2:       TMenuItem;
    N11:                 TMenuItem;
    Delete2:             TMenuItem;
    pmLV0:               TPopupMenu;
    CloseDatabase1:      TMenuItem;
    actRefreshDB:        TAction;
    Refresh1:            TMenuItem;
    N12:                 TMenuItem;
    cbDBName:            TComboBox;
    Label2:              TLabel;
    RzSpacer12:          TRzSpacer;
    BtnRefresh:          TRzToolButton;
    RzSpacer13:          TRzSpacer;
    actRefreshStruct:    TAction;
    pmView:              TPopupMenu;
    OpenTable2:          TMenuItem;
    OpenTableStructure2: TMenuItem;
    N13:                 TMenuItem;
    OutputScript3:       TMenuItem;
    N14:                 TMenuItem;
    DeleteTable3:        TMenuItem;
    actDelView:          TAction;
    actOpenView:         TAction;
    actOpenViewStruct:   TAction;
    actDelTrigger:       TAction;
    actCreateTrigger:    TAction;
    KeyComplete: TSynCompletionProposal;
    FuncComplete: TSynCompletionProposal;
    TableComplete: TSynCompletionProposal;
    N15: TMenuItem;
    OpenSQLWindow2: TMenuItem;
    actWelcomePage: TAction;
    N16: TMenuItem;
    WelcomePage1: TMenuItem;
    actHelp: TAction;
    Help2: TMenuItem;
    actDTS: TAction;
    actHotKeys: TAction;
    SynSqlite: TSynUniSyn;
    actCompact: TAction;
    CompactDatabase1: TMenuItem;
    ViewV1: TMenuItem;
    ObjectTree1: TMenuItem;
    ToolBar1: TMenuItem;
    StatusBar1: TMenuItem;
    HotKeys1: TMenuItem;
    N17: TMenuItem;
    DTSImport1: TMenuItem;
    DataTypeComplete: TSynCompletionProposal;
    actChangePwd: TAction;
    N18: TMenuItem;
    ChangePassword1: TMenuItem;
    actLibMgr: TAction;
    LibraryManager1: TMenuItem;
    actRegister: TAction;
    miReg: TMenuItem;
    N19: TMenuItem;
    N2221: TMenuItem;
    Conn: TRaSQLiteDB;
    Qry: TRaSQLiteQuery;
    Tbl: TRaSQLiteTable;
    CmdQry: TRaSQLiteQuery;
    CmdQryTemp: TRaSQLiteQuery;
    upSQL: TRaSQLiteUpdateSQL;
    procedure actNewExecute(Sender: TObject);
    procedure actOpenExecute(Sender: TObject);
    procedure tvDBClick(Sender: TObject);
    procedure actNewTableExecute(Sender: TObject);
    procedure actModifyTableExecute(Sender: TObject);
    procedure actCloseExecute(Sender: TObject);
    procedure actBackupExecute(Sender: TObject);
    procedure actDeleteTableExecute(Sender: TObject);
    procedure actNewIndexExecute(Sender: TObject);
    procedure actDeleteIndexExecute(Sender: TObject);
    procedure actDemoDBExecute(Sender: TObject);
    procedure miEnglishClick(Sender: TObject);
    procedure miChineseClick(Sender: TObject);
    procedure actSaveExecute(Sender: TObject);
    procedure actExecExecute(Sender: TObject);
    procedure sdSQLTypeChange(Sender: TObject);
    procedure aSynDelete1Execute(Sender: TObject);
    procedure ppMainChange(Sender: TObject);
    procedure actExitExecute(Sender: TObject);
    procedure actOptionsExecute(Sender: TObject);
    procedure btnEditClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure actAboutExecute(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
    procedure ApplicationEvents1Exception(Sender: TObject; E: Exception);
    procedure actOpenTableExecute(Sender: TObject);
    procedure actSQLWindowExecute(Sender: TObject);
    procedure tvDBMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: integer);
    procedure ppMainClose(Sender: TObject; var AllowClose: boolean);
    procedure actRefreshDBExecute(Sender: TObject);
    procedure actOpenStructureExecute(Sender: TObject);
    procedure actRefreshStructExecute(Sender: TObject);
    procedure actOutScriptExecute(Sender: TObject);
    procedure actDeleteObjExecute(Sender: TObject);
    procedure actOpenViewStructExecute(Sender: TObject);
    procedure actOpenViewExecute(Sender: TObject);
    procedure actDelViewExecute(Sender: TObject);
    procedure actDelTriggerExecute(Sender: TObject);
    procedure actCreateTriggerExecute(Sender: TObject);
    procedure cbDBNameChange(Sender: TObject);
    procedure actWelcomePageExecute(Sender: TObject);
    procedure TableCompleteExecute(Kind: SynCompletionType; Sender: TObject;
      var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
    procedure actHelpExecute(Sender: TObject);
    procedure actDTSExecute(Sender: TObject);
    procedure actHotKeysExecute(Sender: TObject);
    procedure actCompactExecute(Sender: TObject);
    procedure ObjectTree1Click(Sender: TObject);
    procedure ToolBar1Click(Sender: TObject);
    procedure StatusBar1Click(Sender: TObject);
    procedure actChangePwdExecute(Sender: TObject);
    procedure actLibMgrExecute(Sender: TObject);
    procedure actRegisterExecute(Sender: TObject);
    procedure KeyCompleteExecute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
    procedure FuncCompleteExecute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
    procedure DataTypeCompleteExecute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
    procedure FormActivate(Sender: TObject);
    procedure N2221Click(Sender: TObject);
  private
    FDatabaseFile: string;
    FCurrentField: string;
    procedure SetDatabaseFile(const Value: string);
    { Private declarations }
  public
    Config:       TSQLiteConfig;
    DatabaseList: TList;
    procedure BuildTree(ATableName: string);
    procedure ShowTableStructure(APage: TPageTableStructure; ATableName: string);
    procedure ShowPOSInfo(ACount, AX, AY: integer);
    procedure ShowInfo;
    function OpenDatabases: boolean;
    procedure OpenLastDB;
    procedure OpenCurrentDB;
    function CheckDBAlreadyOpened(AFileName: string): boolean;
    procedure ShowUnregForm;
    function CheckDoExec(ASQL: string): boolean;
  public
    property DatabaseFile: string Read FDatabaseFile Write SetDatabaseFile;
  end;

var
  FormMain: TFormMain;

  // double click timer
  fClickTime: TDateTime = 0;

implementation

{$R *.dfm}

procedure TFormMain.actAboutExecute(Sender: TObject);
begin
  //  about
  with TFormAbout.Create(Application) do
  begin
    ShowModal;
    Free;
  end;
end;

procedure TFormMain.actBackupExecute(Sender: TObject);
var
  retB: boolean;
begin
  //  back up database
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  sdSave.FileName := EmptyStr;
  if not sdSave.Execute() then
    Exit;
  retB := CopyFile(PChar(DatabaseFile), PChar(sdSave.FileName), True);
  MessageBox(Handle, PChar(IfThen(retB, siLang.GetText('sBackupOK'),
    siLang.GetText('sBackupFail'))),
    PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
end;

procedure TFormMain.actChangePwdExecute(Sender: TObject);
var
  rec: Pointer;
  i: integer;
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  change password
  OpenCurrentDB;
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;
  with TFormChangePwd.Create(Application) do
  begin
    if ShowModal = mrOk then
    begin
      if edtNewPwd.Text <> edtRepeat.Text then
      begin
        MessageBox(Handle,PChar(self.siLang.GetText('sRepeatError')), PChar(self.siLang.GetText('sError')), mb_ok or MB_ICONERROR);
         Free;
         Exit;
      end;

      if not Conn.ChangePassword(edtOldPwd.Text, edtNewPwd.Text) then
      begin
         MessageBox(Handle,PChar(self.siLang.GetText('sOldPwdError')), PChar(self.siLang.GetText('sError')), mb_ok or MB_ICONERROR);
         Free;
         Exit;
      end
      else
      try
        // conn.SQLite3_ReKey(conn.DBHandle, PChar(edtNewPwd.Text), Length(edtNewPwd.Text));
        for i:=0 to DatabaseList.Count - 1 do
        // for rec in DatabaseList do
        begin
          rec := DatabaseList.Items[i];
          if TSQLiteDBRec(rec).FileName = Conn.Database then
          begin
            TSQLiteDBRec(rec).Pwd := edtNewPwd.Text;
            OpenCurrentDB;
            Break;
          end;  
        end;

        MessageBox(Handle,PChar(self.siLang.GetText('sChangePwdOK')), PChar(self.siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
      except
        MessageBox(Handle,PChar(self.siLang.GetText('sChangePwdError')), PChar(self.siLang.GetText('sError')), MB_OK or MB_ICONINFORMATION);
      end;
    end;
    Free;  
  end;  
end;

procedure TFormMain.actCloseExecute(Sender: TObject);
var
  dbName: string;
  i:      integer;
  idx:    integer;
begin
  //  close database

  if DatabaseList.Count = 0 then
    Exit;
  if DatabaseList.Count = 1 then
  begin
    dbName := GetDatabaseName(TSQLiteDBRec(DatabaseList[0]).FileName);
    DatabaseList.Clear;
  end
  else
  begin
    if tvDB.Selected <> nil then
    begin
      if tvDB.Selected.Level = 0 then
      begin
        dbName := GetDatabaseName(TSQLiteDBRec(DatabaseList[GetRootIndex(tvDB.Selected, tvDB)]).FileName);
        DatabaseList.Delete(GetRootIndex(tvDB.Selected, tvDB));
      end
      else
      begin
        dbName := GetDatabaseName(TSQLiteDBRec(
          DatabaseList[GetRootIndex(GetRootNode(tvDB.Selected, tvDB), tvDB)]).FileName);
        DatabaseList.Delete(GetRootIndex(GetRootNode(tvDB.Selected, tvDB), tvDB));
      end;
    end;
  end;
  if OpenDatabases then
    OpenLastDB;
  if DatabaseList.Count = 0 then
  begin
    miEdit.Visible     := True;
    Edit1.Visible      := False;
    Search1.Visible    := False;
    miSQL.Visible      := False;
    tbMain.Visible     := True;
    tbSQL.Visible      := False;
    spPOS.Caption      := EmptyStr;
    BtnRefresh.Visible := False;
    RzSpacer3.Visible  := False;
  end;
  idx := ppMain.ActivePageIndex;
  //  close sheets
  for i := ppMain.PageCount - 1 downto 0 do
  begin
    if GetDatabaseNameFromSheet(ppMain.Pages[i].Caption) = dbName then
      ppMain.Pages[i].Free;
  end;
  if ppMain.PageCount = 0 then
    Exit;
  if ppMain.PageCount > idx then
    ppMain.ActivePageIndex := idx
  else
    ppMain.ActivePageIndex := ppMain.PageCount - 1;
end;

procedure TFormMain.actCompactExecute(Sender: TObject);
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  compact database
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;
  CmdQry.Close;
  CmdQry.SQL.Text := 'VACUUM';
  try
    CmdQry.ExecSQL;
    MessageBox(Handle,PChar(siLang.GetText('sCompactOK')),PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
  except
    on E: Exception do
      MessageBox(Handle, PChar(E.Message), PChar(siLang.GetText('sError')),
          MB_OK or MB_ICONERROR);
  end;  
end;

procedure TFormMain.actCreateTriggerExecute(Sender: TObject);
begin
  //  create trigger
end;

procedure TFormMain.actDeleteIndexExecute(Sender: TObject);
var
  hql: string;
begin
  //  delete index
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  if tvDB.Selected = nil then
    Exit;
  if tvDB.Selected.Level <> 2 then
    Exit;
  if Pos('sqlite_autoindex', tvDB.Selected.Text) > 0 then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sCantDelAutoIndex')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  if MessageBox(Handle, PChar(siLang.GetText('sConfirmDelIndex')),
    PChar(siLang.GetText('sHint')), MB_YESNO or MB_ICONINFORMATION) = idNo then
    Exit;

  hql := 'drop index ' + tvdb.Selected.Text;
  CmdQry.Close;
  CmdQry.SQL.Text := LowerCase(hql);
  try
    CmdQry.ExecSQL;
  except
    on E: Exception do
      MessageBox(Handle, PChar(E.Message), PChar(siLang.GetText('sError')),
        MB_OK or MB_ICONERROR);
  end;
  BuildTree(tvdb.Selected.Text);
end;

procedure TFormMain.actDeleteObjExecute(Sender: TObject);
begin
  //  delete lv2 objects
  OpenCurrentDB;
  case tvDB.Selected.ImageIndex of
    9: actDeleteIndexExecute(nil);       // index
    59: actDelTriggerExecute(nil);       // trigger
  end;
end;

procedure TFormMain.actDeleteTableExecute(Sender: TObject);
var
  hql: string;
begin
  //  delete table
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  if tvDB.Selected = nil then
    Exit;
  if tvDB.Selected.Level <> 1 then
    Exit;
  if tvDB.Selected.ImageIndex = 10 then
  begin
    if MessageBox(Handle, PChar(siLang.GetText('sConfirmDelTable')),
      PChar(siLang.GetText('sHint')), MB_YESNO or MB_ICONINFORMATION) = idNo then
      Exit;
    hql := 'drop table ' + tvDb.Selected.Text;
    CmdQry.Close;
    CmdQry.SQL.Text := LowerCase(hql);
    try
      CmdQry.ExecSQL;
    except
      on E: Exception do
        MessageBox(Handle, PChar(E.Message), PChar(siLang.GetText('sError')),
          MB_OK or MB_ICONERROR);
    end;
  end
  else
  begin
    // delete view
    if MessageBox(Handle, PChar(siLang.GetText('sConfirmDelView')),
      PChar(siLang.GetText('sHint')), MB_YESNO or MB_ICONINFORMATION) = idNo then
      Exit;
    hql := 'drop view ' + tvDb.Selected.Text;
    CmdQry.Close;
    CmdQry.SQL.Text := LowerCase(hql);
    try
      CmdQry.ExecSQL;
    except
      on E: Exception do
        MessageBox(Handle, PChar(E.Message), PChar(siLang.GetText('sError')),
          MB_OK or MB_ICONERROR);
    end;
  end;

  BuildTree(EmptyStr);
end;

procedure TFormMain.actDelTriggerExecute(Sender: TObject);
var
  hql: string;
begin
  //  delete trigger
  OpenCurrentDB;
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  if tvDB.Selected = nil then
    Exit;
  if tvDB.Selected.Level <> 2 then
    Exit;

  if MessageBox(Handle, PChar(siLang.GetText('sConfirmDelTrigger')),
    PChar(siLang.GetText('sHint')), MB_YESNO or MB_ICONINFORMATION) = idNo then
    Exit;

  hql := 'drop trigger ' + tvdb.Selected.Text;
  CmdQry.Close;
  CmdQry.SQL.Text := LowerCase(hql);
  try
    CmdQry.ExecSQL;
  except
    on E: Exception do
      MessageBox(Handle, PChar(E.Message), PChar(siLang.GetText('sError')),
        MB_OK or MB_ICONERROR);
  end;
  BuildTree(tvdb.Selected.Text);
end;

procedure TFormMain.actDelViewExecute(Sender: TObject);
begin
  actDeleteTableExecute(nil);
end;

procedure TFormMain.actDemoDBExecute(Sender: TObject);
var
  fn: string;
begin
  //  demo db
  fn := ExtractFilePath(ParamStr(0)) + 'Demo.db';
  Conn.Database := fn;
  try
    Conn.Open;
  except
    MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
    Exit;
  end;
  
  Qry.SQL.Text :=
    'create table testSL(uid int primary key, uname varchar(50) not null, uage int)';
  try
    CmdQry.ExecSQL;
  except
    on E: Exception do
      MessageBox(Handle, PChar(E.Message), PChar(siLang.GetText('sError')),
        MB_OK or MB_ICONERROR);
  end;
end;

procedure TFormMain.actDTSExecute(Sender: TObject);
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  DTS import data
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
    Exit;
  end;

  with TFormDTS.Create(Application) do
  begin
    TableName := tvDB.Selected.Text;
    ShowModal;
    Free;
  end;  

end;

procedure TFormMain.actExecExecute(Sender: TObject);
var
  hqls: TStringList;
  s:    string;
  i: Integer;
  pg:   TPageSQLWindow;
begin
  //  execute sql
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
    Exit;
  end;

  pg := TPageSQLWindow(ppMain.ActivePage);

  pg.mmResult.Lines.Clear;
  pg.qryData.Close;
  pg.cdsData.Close;
  (pg.cgvw.DataController as IcxCustomGridDataController).DeleteAllItems;
  if not Config.BatchSQL then
  begin
    if pg.mmSQL.SelText = EmptyStr then
      pg.qryData.SQL.Text := lowercase(pg.mmSQL.Lines.Text)
    else
      pg.qryData.SQL.Text := lowercase(pg.mmSQL.SelText);

    if CheckDoExec(pg.qryData.SQL.Text) then
    begin
      try
        pg.qryData.ExecSQL;
        pg.mmResult.Lines.Add(siLang.GetText('sExecuteOK'));
        pg.ppResult.ActivePageIndex := 1;
      except
        on E: Exception do
        begin
          pg.mmResult.Lines.Add(E.Message);
          pg.qryData.Close;
          pg.cdsData.Close;
          pg.ppResult.ActivePageIndex := 1;
        end;
      end;
    end
    else if Pos('select', LowerCase(pg.qryData.SQL.Text)) > 0 then
    begin
      try
        pg.qryData.Open;
        pg.cdsData.Open;
        pg.mmResult.Lines.Add(Format(siLang.GetText('sFmtAffected'),
          [pg.cdsData.RecordCount]));
        pg.ppResult.ActivePageIndex := 0;
        pg.cgvw.DataController.CreateAllItems;
      except
        on E: Exception do
          begin
            try
              pg.qryData.ExecSQL;
              pg.mmResult.Lines.Add(siLang.GetText('sExecuteOK'));
              pg.ppResult.ActivePageIndex := 1;
            except
              on Ex: Exception do
              begin
                pg.mmResult.Lines.Add(Ex.Message);
                pg.qryData.Close;
                pg.cdsData.Close;
                pg.ppResult.ActivePageIndex := 1;
              end;
            end;
          end;
      end;
    end;
  end
  else
  begin
    //  batch sql
    if pg.mmSQL.SelText = EmptyStr then
      hqls := GenerateBatchSQL(pg.mmSQL.Lines.Text)
    else
      hqls := GenerateBatchSQL(pg.mmSQL.SelText);
    for i:=0 to hqls.Count - 1 do
    // for s in hqls do
    begin
      s := hqls[i];
      pg.qryData.Close;
      pg.cdsData.Close;
      pg.qryData.SQL.Text := LowerCase(s);
      if CheckDoExec(pg.qryData.SQL.Text) then
      begin
        try
          pg.qryData.ExecSQL;
          pg.mmResult.Lines.Add(siLang.GetText('sExecuteOK'));
          pg.ppResult.ActivePageIndex := 1;
        except
          on E: Exception do
          begin
            pg.mmResult.Lines.Add(E.Message);
            pg.qryData.Close;
            pg.cdsData.Close;
            pg.ppResult.ActivePageIndex := 1;
          end;

        end;
      end
      else if Pos('select', LowerCase(pg.qryData.SQL.Text)) > 0 then
      begin
        try
          pg.qryData.Open;
          pg.cdsData.Open;
          pg.mmResult.Lines.Add(Format(siLang.GetText('sFmtAffected'),
            [pg.cdsData.RecordCount]));
          pg.ppResult.ActivePageIndex := 0;
          (pg.cgvw.DataController as IcxCustomGridDataController).DeleteAllItems;
          pg.cgvw.DataController.CreateAllItems;
        except
          on E: Exception do
          begin
            try
              pg.qryData.ExecSQL;
              pg.mmResult.Lines.Add(siLang.GetText('sExecuteOK'));
              pg.ppResult.ActivePageIndex := 1;
            except
              on Ex: Exception do
              begin
                pg.mmResult.Lines.Add(Ex.Message);
                pg.qryData.Close;
                pg.cdsData.Close;
                pg.ppResult.ActivePageIndex := 1;
              end;

            end;
          end;

        end;
      end;
    end;
  end;

end;

procedure TFormMain.actExitExecute(Sender: TObject);
begin
  Close;
end;

procedure TFormMain.actHelpExecute(Sender: TObject);
var
  fn: string;
begin
  //  help index.html
  fn := ExtractFilePath(ParamStr(0))+'Help\SQLite3.chm';
  if FileExists(fn) then
    ShellExecute(0,'open',PChar(fn), nil, nil, SW_SHOW);
end;

procedure TFormMain.actHotKeysExecute(Sender: TObject);
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  config hot keys
  with TFormHotKey.Create(Application) do
  begin
    hkKey.HotKey := KeyComplete.ShortCut;
    hkFunc.HotKey := FuncComplete.ShortCut;
    hkDataType.HotKey := DataTypeComplete.ShortCut;
    if ShowModal = mrOk then
    begin
      Config.HKKey := hkKey.HotKey;
      Config.HKFunc := hkFunc.HotKey;
      Config.HKDataType := hkDataType.HotKey;
      KeyComplete.ShortCut := Config.HKKey;
      FuncComplete.ShortCut := Config.HKFunc;
      DataTypeComplete.ShortCut := Config.HKDataType;
    end;
    Free;  
  end;  
end;

procedure TFormMain.actLibMgrExecute(Sender: TObject);
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  library manager
  with TFormLibMgr.Create(Application) do
  begin
    lblCurrentLib.Caption := Conn.DriverDLL;
    if ShowModal = mrOk then
    begin
      Conn.DriverDLL := lblCurrentLib.Caption;
      Config.CurrentLib := lblCurrentLib.Caption;
    end;
    Free;  
  end;  
end;

procedure TFormMain.actModifyTableExecute(Sender: TObject);
var
  hql:     string;
  tblName: string;
  i:       integer;
  item:    TListItem;
  DBInfo:  TList;
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  modify table
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  if tvDB.Selected = nil then
    Exit;
  if tvDB.Selected.Level <> 1 then
    Exit;

  if tvDB.Selected.ImageIndex <> 10 then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotOnView')),
      PChar(siLang.GetText('sHint')),
      MB_OK or MB_ICONWARNING);
    Exit;
  end;

  if config.NoModify then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNoModify')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  with TFormTableStruct.Create(Application) do
  begin

    EditMode          := emEdit;
    TableName         := tvDB.Selected.Text;
    tblName           := TableName;
    edtTableName.Text := TableName;

    DBInfo := TList.Create;
    Conn.GetTableInfo(tvDB.Selected.Text, DBInfo);
    for i := 0 to DBInfo.Count - 1 do
    begin
      with TRaSQLiteField(DBInfo[i]) do
      begin
        item         := lvTable.Items.Add;
        item.Caption := FieldName;
        item.SubItems.Add(FieldType);
        if FieldPK = 1 then
          item.SubItems.Add('PK')
        else
          item.SubItems.Add(EmptyStr);
        item.SubItems.Add(FieldDefault);
      end;
    end;

    DBInfo.Free;
    // lvTable.Items     := self.lvTable.Items;
    if ShowModal = mrOk then
    begin
      //  alter table
      if tblName = edtTableName.Text then
      begin
        // use temp table
        hql := GenerateModifyTableSQL(edtTableName.Text + '_Sqlite_Temp_Table', lvTable);
        if Pos('(', hql) > 0 then
        begin
          CmdQry.Close;
          CmdQry.SQL.Text := LowerCase(hql);
          try
            CmdQry.ExecSQL;
            CmdQryTemp.Close;
            CmdQryTemp.SQL.Text := 'select * from ' + tblName;
            CmdQryTemp.Open;

            CopyDataToNewTable(edtTableName.Text + '_Sqlite_Temp_Table',
              edtTableName.Text, CmdQry, CmdQryTemp, lvTable);
            CmdQry.Close;
            CmdQryTemp.Close;
            // drop original table
            CmdQry.SQL.Text := 'drop table ' + tblName;
            CmdQry.ExecSQL;
            CmdQry.Close;
            CmdQry.SQL.Text :=
              'alter table ' + edtTableName.Text + '_Sqlite_Temp_Table' +
              ' rename to ' + tblName;
            CmdQry.ExecSQL;
            CmdQry.Close;
            Tbl.Close;
            Tbl.TableName := tblName;
            Tbl.Open;

            BuildTree(tblName);
          except
            on E: Exception do
              MessageBox(Handle, PChar(E.Message), PChar(self.siLang.GetText('sError')),
                MB_OK or MB_ICONERROR);
          end;
        end
        else
          MessageBox(Handle, PChar(self.siLang.GetText('sFieldIndexZero')),
            PChar(self.siLang.GetText('sError')), MB_OK or MB_ICONERROR);

      end
      else
      begin
        // directory create new table
        hql := GenerateModifyTableSQL(edtTableName.Text, lvTable);
        if Pos('(', hql) > 0 then
        begin
          CmdQry.Close;
          CmdQry.SQL.Text := LowerCase(hql);
          try
            CmdQry.ExecSQL;
            CmdQryTemp.Close;
            CmdQryTemp.SQL.Text := 'select * from ' + tblName;
            CmdQryTemp.Open;

            CopyDataToNewTable(edtTableName.Text, tblName, CmdQry, CmdQryTemp, lvTable);
            CmdQry.Close;
            CmdQryTemp.Close;
            // drop original table
            CmdQry.SQL.Text := 'drop table ' + tblName;
            CmdQry.ExecSQL;
            CmdQry.Close;
            Tbl.Close;
            Tbl.TableName := edtTableName.Text;
            Tbl.Open;

            BuildTree(edtTableName.Text);
          except
            on E: Exception do
              MessageBox(Handle, PChar(E.Message), PChar(self.siLang.GetText('sError')),
                MB_OK or MB_ICONERROR);
          end;
        end
        else
          MessageBox(Handle, PChar(Self.siLang.GetText('sFieldIndexZero')),
            PChar(Self.siLang.GetText('sError')), MB_OK or MB_ICONERROR);
      end;

    end;
    Free;
  end;

end;

procedure TFormMain.actNewExecute(Sender: TObject);
var
  rec: TSQLiteDBRec;
begin
  //  new database
  if not sdSave.Execute() then
    Exit;
  if Conn.Connected then
    Conn.Close;
  if not CheckDBAlreadyOpened(sdSave.FileName) then
  begin
    with TFormInputPwd.Create(Application) do
    begin
      if ShowModal = mrOk then
      begin
        rec:= TSQLiteDBRec.Create;
        rec.FileName := sdSave.FileName;
        rec.Pwd := edtPwd.Text;
        DatabaseList.Add(rec);
        if OpenDatabases then
          OpenLastDB;
      end;
      Free;  
    end;
  end;
end;

procedure TFormMain.actNewIndexExecute(Sender: TObject);
var
  hql: string;
  fd:  TField;
  i: Integer;
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  create index
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;

  if tvDB.Selected = nil then
    Exit;
  if tvDB.Selected.Level <> 1 then
    Exit;

  if tvDB.Selected.ImageIndex <> 10 then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotOnView')),
      PChar(siLang.GetText('sHint')),
      MB_OK or MB_ICONWARNING);
    Exit;
  end;

  with TFormIndexInfo.Create(Application) do
  begin
    cbField.Clear;
    for i:=0 to Tbl.Fields.Count - 1 do
    begin
      fd := Tbl.Fields[i];
      cbField.Items.Add(fd.FieldName);
    end;  
//    for fd in Tbl.Fields do
//      cbField.Items.Add(fd.FieldName);
    if ShowModal = mrOk then
    begin
      //  generate SQL
      if edtIndexName.Text <> EmptyStr then
      begin
        if cbField.Text <> EmptyStr then
        begin
          hql := GenerateCreateIndexSQL(tvDB.Selected.Text, edtIndexName.Text,
            cbField.Text, cbOrder.Text, cbUniq.ItemIndex = 1);
          CmdQry.Close;
          CmdQry.SQL.Text := LowerCase(hql);
          try
            CmdQry.ExecSQL;
          except
            on E: Exception do
              MessageBox(Handle, PChar(E.Message), PChar(self.siLang.GetText('sError')),
                MB_OK or MB_ICONERROR);
          end;
          BuildTree(tvDB.Selected.Text);
        end;
      end;
    end;
    Free;
  end;

end;

procedure TFormMain.actNewTableExecute(Sender: TObject);
var
  hql: string;
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  new Table
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;
  with TFormTableStruct.Create(Application) do
  begin
    EditMode := emAdd;
    if ShowModal = mrOk then
    begin

      //  generate sql and create table
      if lvTable.Items.Count > 0 then
      begin
        hql := GenerateCreateTableSQL(edtTableName.Text, lvTable);
        CmdQry.Close;
        CmdQry.SQL.Text := LowerCase(hql);
        try
          CmdQry.ExecSQL;
        except
          on E: Exception do
            MessageBox(Handle, PChar(E.Message), PChar(Self.siLang.GetText('sError')),
              MB_OK or MB_ICONERROR);
        end;
        BuildTree(edtTableName.Text);
      end
      else
        MessageBox(Handle, PChar(self.siLang.GetText('sFieldIndexZero')),
          PChar(Self.siLang.GetText('sError')), MB_OK or MB_ICONERROR);

    end;
    Free;
  end;
end;

procedure TFormMain.actOpenExecute(Sender: TObject);
var
  rec : TSQLiteDBRec;

begin
  //  open database
  if not odOpen.Execute() then
    Exit;
  if not CheckDBAlreadyOpened(odOpen.FileName) then
  begin
    with TFormInputPwd.Create(Application) do
    begin
      if ShowModal = mrOk then
      begin
        rec := TSQLiteDBRec.Create;
        rec.FileName := odOpen.FileName;
        rec.Pwd := edtPwd.Text;
        DatabaseList.Add(rec);

        if OpenDatabases then
          OpenLastDB;
      end;
      Free;
    end;
  end;
end;

procedure TFormMain.actOpenStructureExecute(Sender: TObject);
var
  pg: TPageTableStructure;
begin
  //  open table structure
  OpenCurrentDB;
  pg := TPageTableStructure.Create(ppMain);
  pg.PageControl := ppMain;
  ShowTableStructure(pg, tvDB.Selected.Text);
  pg.Caption        := Format(siLang.GetText('sFmtStructure'),
    [GetDatabaseName(Conn.Database), tvDB.Selected.Text]);
  ppMain.ActivePage := pg;
end;

procedure TFormMain.actOpenTableExecute(Sender: TObject);
var
  pg: TPageTableData;
begin
  //  open table
  OpenCurrentDB;
  pg           := TPageTableData.Create(ppMain);
  pg.PageControl := ppMain;
  pg.Connection := Conn;
  pg.TableName := tvDB.Selected.Text;
  pg.Caption   := Format(siLang.GetText('sFmtData'), [GetDatabaseName(Conn.Database),
    tvDB.Selected.Text]);
  ppMain.ActivePage := pg;
end;

procedure TFormMain.actOpenViewExecute(Sender: TObject);
begin
  actOpenTableExecute(nil);
  with TPageTableData(ppMain.ActivePage) do
  begin
    cgvw.OptionsData.Editing := False;
    dbnvTbl.Enabled := False;
    btnEdit.Enabled := False;
  end;
end;

procedure TFormMain.actOpenViewStructExecute(Sender: TObject);
begin
  actOpenStructureExecute(nil);
end;

procedure TFormMain.actOptionsExecute(Sender: TObject);
var
  i: integer;
begin
  //  options
  with TFormOptions.Create(Application) do
  begin
    //  load config
    chkBatchSQL.Checked       := Config.BatchSQL;
    chkWordWrap.Checked       := Config.WordWrap;
    chkNotAllowModify.Checked := Config.NoModify;
    chkReadonly.Checked       := Config.DataReadonly;
    RadioGroup1.ItemIndex     := Config.EncodeFmt;
    chkUTF8File.Checked := Config.UTF8FileName;
    if ShowModal = mrOk then
    begin
      //  save options
      config.BatchSQL     := chkBatchSQL.Checked;
      Config.WordWrap     := chkWordWrap.Checked;
      Config.NoModify     := chkNotAllowModify.Checked;
      Config.DataReadonly := chkReadonly.Checked;
      Config.EncodeFmt    := RadioGroup1.ItemIndex;

      config.UTF8FileName := chkUTF8File.Checked;

      for i := 0 to ppMain.PageCount - 1 do
      begin
        if ppMain.Pages[i].ClassName = 'TPageSQLWindow' then
          TPageSQLWindow(ppMain.Pages[i]).mmSQL.WordWrap.Enabled :=
            Config.WordWrap;
      end;
      // mmSQL.WordWrap.Enabled := Config.WordWrap;

      if Config.EncodeFmt = 0 then
        conn.CharacterEncoding := 'STANDARD'
      else if Config.EncodeFmt = 1 then
        Conn.CharacterEncoding := 'UTF8';
      conn.UTF8DBName := Config.UTF8FileName;
    end;
    Free;
  end;
end;

procedure TFormMain.actOutScriptExecute(Sender: TObject);
var
  pg: TPageSQLWindow;
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  outpur script
  OpenCurrentDB;
  pg         := TPageSQLWindow.Create(ppMain);
  pg.PageControl := ppMain;
  pg.Connection := Conn;
  pg.Caption := Format(siLang.GetText('sFmtSQL'), [GetDatabaseName(Conn.Database)]);
  ppMain.ActivePage := pg;
  cbDBName.ItemIndex := cbDBName.Items.IndexOf(GetDatabaseName(Conn.Database));

  // script
  case tvDB.Selected.ImageIndex of
    10: pg.mmSQL.Lines.Text := GetTableSQL(Conn, tvDB.Selected.Text);  // table
    9: pg.mmSQL.Lines.Text  := GetIndexSQL(Conn, tvDB.Selected.Text,
        GetTableNameFromNode(tvDB.Selected));   // index
    59: pg.mmSQL.Lines.Text := GetTriggerSQL(Conn, tvDB.Selected.Text,
        GetTableNameFromNode(tvDB.Selected));  // trigger
    60: pg.mmSQL.Lines.Text := GetViewSQL(Conn, tvDB.Selected.Text);  // view
  end;
end;

procedure TFormMain.actRefreshDBExecute(Sender: TObject);
begin
  //  refresh database
  BuildTree(EmptyStr);
end;

procedure TFormMain.actRefreshStructExecute(Sender: TObject);
begin
  //  refresh table structure
  ShowTableStructure(
    TPageTableStructure(ppMain.ActivePage),
    GetTableNameFromSheet(ppMain.ActivePage.Caption));
end;

procedure TFormMain.actRegisterExecute(Sender: TObject);
begin
  // register
  ShowUnregForm;
end;

procedure TFormMain.actSaveExecute(Sender: TObject);
begin
  {$IFDEF TRIAL}
  ShowUnregForm;
  Exit;
  {$ENDIF}
  //  save
  if ppMain.ActivePage.ClassName <> 'TPageSQLWindow' then
    Exit;
  if sdSQL.Execute() then
    TPageSQLWindow(ppMain.ActivePage).mmSQL.Lines.SaveToFile(sdSQL.FileName);
end;

procedure TFormMain.actSQLWindowExecute(Sender: TObject);
var
  pg: TPageSQLWindow;
begin
  //  open sql window
  OpenCurrentDB;
  if not Conn.Connected then
  begin
    MessageBox(Handle, PChar(siLang.GetText('sNotConnected')),
      PChar(siLang.GetText('sHint')), MB_OK or MB_ICONINFORMATION);
    Exit;
  end;
  pg         := TPageSQLWindow.Create(ppMain);
  pg.PageControl := ppMain;
  pg.Connection := Conn;
  pg.Caption := Format(siLang.GetText('sFmtSQL'), [GetDatabaseName(Conn.Database)]);
  ppMain.ActivePage := pg;
  cbDBName.ItemIndex := cbDBName.Items.IndexOf(GetDatabaseName(Conn.Database));
end;

procedure TFormMain.actWelcomePageExecute(Sender: TObject);
var
  i: Integer;
  hasPage: Boolean;
  pg: TPageWelcome;
begin
  //  show welcome page
  hasPage := False;
  for i := 0 to ppMain.PageCount - 1 do
  begin
    if ppMain.Pages[i].ClassName = 'TPageWelcome' then
    begin
      hasPage := True;
      Break;
    end;  
  end;  
  if not hasPage then
  begin
    pg:= TPageWelcome.Create(ppMain);
    pg.PageControl := ppMain;
    ppMain.ActivePage := pg;
  end;
end;

procedure TFormMain.ApplicationEvents1Exception(Sender: TObject; E: Exception);
begin
  // do nothing
  // ShowMessage(e.Message);
end;

procedure TFormMain.aSynDelete1Execute(Sender: TObject);
begin
  TPageSQLWindow(ppMain.ActivePage).mmSQL.SelText := EmptyStr;
end;

procedure TFormMain.btnEditClick(Sender: TObject);
begin
  if FCurrentField = EmptyStr then
    Exit;
  if Tbl.FieldByName(FCurrentField).DataType = ftBlob then
  begin
    //  edit blob
    Blob.DataField := FCurrentField;
    with TFormEditBlob.Create(Application, Blob) do
    begin
      Caption := self.siLang.GetText('sEditBlob') + FCurrentField;
      if ShowModal = mrOk then
      begin
        if leFile.Text = '(NULL)' then
          Blob.SaveToDatabase(EmptyStr)
        else if leFile.Text <> '(BLOB)' then
          blob.SaveToDatabase(leFile.Text);
      end;
      Free;
    end;

    fClickTime := 0;
  end;

end;

procedure TFormMain.BuildTree(ATableName: string);
var

  Node:      TTreeNode;
  subNode:   TTreeNode;
  idxNode:   TTreeNode;
  fdNode:    TTreeNode;
  s0: Pointer;
  s, s1: string;
  i:         integer;
  sts:       TSQLiteTableStruct;
  sds:       TSQLiteDatabaseStruct;
  x, y, z: Integer;
begin
  tvDB.Items.Clear;
  for x:=0 to DatabaseList.Count - 1 do
  // for s0 in DatabaseList do
  begin
    s0 := DatabaseList.Items[x];
    Conn.Close;
    Conn.Database := TSQLiteDBRec(s0).FileName;
    conn.Password := TSQLiteDBRec(s0).Pwd;
    try
      Conn.Open;
    except
      MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
      Exit;
    end;
    Node := tvDB.Items.Add(nil, GetDatabaseName(TSQLiteDBRec(s0).FileName));
    Node.ImageIndex := 11;
    Node.SelectedIndex := 11;

    sds := TSQLiteDatabaseStruct.Create;
    sds.Connection := Conn;
    for y:=0 to sds.TableList.count - 1 do
    // for s in sds.TableList do
    begin
      s := sds.TableList[y];
      subNode       := tvDB.Items.AddChild(Node, s);
      subNode.ImageIndex := 10;
      subNode.SelectedIndex := 10;
      sts           := TSQLiteTableStruct.Create;
      sts.Connection := Conn;
      sts.TableName := s;

      idxNode := tvDB.Items.AddChild(subNode, 'Fields');
      idxNode.ImageIndex := 63;
      idxNode.SelectedIndex := 63;
      for z:=0 to sts.FieldsList.Count - 1 do
      // for s1 in sts.FieldsList do
      begin
        s1 := sts.FieldsList[z];
        fdNode := tvDB.Items.AddChildFirst(idxNode, s1);
        fdNode.ImageIndex := 62;
        fdNode.SelectedIndex := 62;
      end;

      for z:=0 to sts.IndexList.Count - 1 do
      // for s1 in sts.IndexList do
      begin
        s1 := sts.IndexList[z];
        idxNode := tvDB.Items.AddChild(subNode, s1);
        idxNode.ImageIndex := 9;
        idxNode.SelectedIndex := 9;
      end;

      for z:=0 to sts.TriggerList.Count - 1 do
      // for s1 in sts.TriggerList do
      begin
        s1 := sts.TriggerList[z];
        idxNode := tvDB.Items.AddChild(subNode, s1);
        idxNode.ImageIndex := 59;
        idxNode.SelectedIndex := 59;
      end;
    end;
    for y:=0 to sds.ViewList.Count - 1 do
    // for s in sds.ViewList do
    begin
      s :=sds.ViewList[y];
      subNode := tvDB.Items.AddChild(Node, s);
      subNode.ImageIndex := 60;
      subNode.SelectedIndex := 60;
    end;
  end;

  // tvDB.FullExpand;
  for i := 0 to tvDB.Items.Count - 1 do
  begin
    if tvDB.Items[i].Text = ATableName then
    begin
      tvDB.Selected := tvDB.Items[i];
      tvDBClick(nil);
      Break;
    end;
  end;

end;

procedure TFormMain.cbDBNameChange(Sender: TObject);
var
  dbName: string;
begin
  //  change database
  dbName := TSQLiteDBRec(DatabaseList[cbDBName.ItemIndex]).FileName;
  Conn.Close;
  Conn.Database := dbName;
  conn.Password := TSQLiteDBRec(DatabaseList[cbDBName.ItemIndex]).Pwd;
  try
    Conn.Open;
  except
    MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
    Exit;
  end;
end;

function TFormMain.CheckDBAlreadyOpened(AFileName: string): boolean;
var
  obj: Pointer;
  i: integer;
begin
  Result := False;
  for i:=0 to DatabaseList.Count - 1 do
  // for obj in DatabaseList do
  begin
    obj := DatabaseList.Items[i];
    if TSQLiteDBRec(obj).FileName = AFileName then
    begin
      Result := True;
      Break;
    end;  
  end;
    
end;

function TFormMain.CheckDoExec(ASQL: string): boolean;
var
  s: string;
begin
  Result := False;
  s := LowerCase(Trim(ASQL));
  if (Pos('create', s) > 0) or
     (Pos('alter', s) > 0) or
     (Pos('drop', s) > 0) or
     (Pos('insert', s) > 0) or
     (Pos('update', s) > 0) or
     (Pos('delete', s) > 0) or
     (Pos('pragma', s) > 0) then
  begin
    Result := True;
    Exit;
  end;
  if (AnsiStartsStr('if', s)) or (AnsiStartsStr('raise', s)) or (AnsiStartsStr('set', s)) then
  begin
    Result := True;
    Exit;
  end; 

end;

procedure TFormMain.DataTypeCompleteExecute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
begin
  {$IFDEF TRIAL}
  CanExecute:=false;
  Exit;
  {$ENDIF}
end;

procedure TFormMain.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
  DatabaseList.Free;
  Config.SaveToFile(ChangeFileExt(ParamStr(0), '.ini'));
  config.Free;
end;

procedure TFormMain.FormCreate(Sender: TObject);
var
  fp:   string;
  lost: boolean;
  pg: TPageWelcome;
begin
  FCurrentField := EmptyStr;
  Config        := TSQLiteConfig.Create;
  DatabaseList  := TList.Create;
  Config.LoadFromFile(ChangeFileExt(ParamStr(0), '.ini'));
  if Config.Language = 2 then
    miChineseClick(nil)
  else
    miEnglishClick(nil);
  conn.DriverDLL := config.CurrentLib;
  if Config.EncodeFmt = 0 then
    conn.CharacterEncoding := 'STANDARD'
  else if Config.EncodeFmt = 1 then
    Conn.CharacterEncoding := 'UTF8';
  conn.UTF8DBName := Config.UTF8FileName;
    //  check code hint file
  lost := False;
  fp   := ExtractFilePath(ParamStr(0)) + '\CodeHint\';
  if not FileExists(fp + 'Keywords.dat') then
    lost := True;
  if not FileExists(fp + 'Keywords_ins.dat') then
    lost := True;
  if not FileExists(fp + 'Functions.dat') then
    lost := True;
  if not FileExists(fp + 'Functions_ins.dat') then
    lost := True;

  if lost then
  begin
    MessageBox(handle,PChar(siLang.GetText('sNoHintFile')),PChar(siLang.GetText('sHint')), MB_OK or MB_ICONWARNING)
  end
  else
  begin
    //  load code hint
    KeyComplete.InsertList.LoadFromFile(fp + 'Keywords_ins.dat');
    KeyComplete.ItemList.LoadFromFile(fp + 'Keywords.dat');
    FuncComplete.InsertList.LoadFromFile(fp + 'Functions_ins.dat');
    FuncComplete.ItemList.LoadFromFile(fp + 'Functions.dat');
  end;
  pg := TPageWelcome.Create(ppMain);
  pg.PageControl := ppMain;
  ppMain.ActivePage := pg;

  //  use sqlite syntax?
  if FileExists(fp + 'SQLite.xml') then
  begin
    Config.UseSqliteSyntax := True;
    SynSqlite.LoadFromFile(fp + 'SQLite.xml');
  end
  else
    Config.UseSqliteSyntax := False;

  //  view objects
  Splitter1.Visible := Config.ViewObjTree;
  tvDB.Visible := Config.ViewObjTree;
  ObjectTree1.Checked := Config.ViewObjTree;

  tbMain.Visible := Config.ViewToolbar;
  ToolBar1.Checked := Config.ViewToolbar;

  sbMain.Visible := Config.ViewStatusbar;
  StatusBar1.Checked := Config.ViewStatusbar;

  KeyComplete.ShortCut := Config.HKKey;
  FuncComplete.ShortCut := Config.HKFunc;
  DataTypeComplete.ShortCut := Config.HKDataType;
  {$IFDEF TRIAL}
  miReg.Visible := True;
  {$ENDIF}
end;

procedure TFormMain.FuncCompleteExecute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
begin
  {$IFDEF TRIAL}
  CanExecute:=false;
  Exit;
  {$ENDIF}
end;

procedure TFormMain.KeyCompleteExecute(Kind: SynCompletionType; Sender: TObject; var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean);
begin
  {$IFDEF TRIAL}
  CanExecute:=false;
  Exit;
  {$ENDIF}
end;

procedure TFormMain.miChineseClick(Sender: TObject);
begin
  siLang.ActiveLanguage := 2;

  FindDlgLanguageName   := 'Chinese';
  SetSynEditLanguage('Chinese');

  config.Language       := 2;
  ShowInfo;
  //  request restart program
  if Sender <> nil then
    MessageBox(Handle,PChar(siLang.GetText('sRestartPro')),PChar(siLang.GetText('sHint')),MB_OK or MB_ICONINFORMATION);
end;

procedure TFormMain.miEnglishClick(Sender: TObject);
begin
  siLang.ActiveLanguage := 1;

  FindDlgLanguageName   := 'English';
  SetSynEditLanguage('English');

  config.Language       := 1;
  ShowInfo;
  //  request restart program
  if Sender <> nil then
    MessageBox(Handle,PChar(siLang.GetText('sRestartPro')),PChar(siLang.GetText('sHint')),MB_OK or MB_ICONINFORMATION);
end;

procedure TFormMain.ObjectTree1Click(Sender: TObject);
begin
  //  view object tree
  Config.ViewObjTree := not Config.ViewObjTree;
  Splitter1.Visible := Config.ViewObjTree;
  tvDB.Visible := Config.ViewObjTree;
  ObjectTree1.Checked := Config.ViewObjTree;
end;

procedure TFormMain.ToolBar1Click(Sender: TObject);
begin
  //  view tool bar
  Config.ViewToolbar := not Config.ViewToolbar;
  ppMainChange(nil);
  ToolBar1.Checked := Config.ViewToolbar;
end;

procedure TFormMain.OpenCurrentDB;
var
  nd:  TTreeNode;
  idx: integer;
begin
  if (not Conn.Connected) or ((Conn.Connected) and (Conn.Database = '.db')) then
  begin
    if tvDB.Selected <> nil then
    begin
      nd  := GetRootNode(tvDB.Selected, tvDB);
      idx := GetRootIndex(nd, tvDB);      
      Conn.Close;
      Conn.Database := TSQLiteDBRec(DatabaseList[idx]).FileName;
      conn.Password := TSQLiteDBRec(DatabaseList[idx]).Pwd;
      try
        Conn.Open;
      except
        MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
        Exit;
      end;
    end;
  end;
end;

function TFormMain.OpenDatabases: Boolean;
var
  s: Pointer;
  i: Integer;
begin
  Result := true;
  {$IFDEF TRIAL}
  self.Caption := 'SNDA SQLite Tool (Trial)';
  {$ELSE}
  self.Caption := 'SNDA SQLite Tool';
  {$ENDIF}
  Conn.Close;
  cbDBName.Items.Clear;
  for i:= 0 to DatabaseList.Count - 1 do
  // for s in DatabaseList do
  begin
    s := DatabaseList.Items[i];
    Conn.Close;
    spStat.Caption := siLang.GetText('sReady');
//    if FDatabaseFile <> EmptyStr then
    begin
      Conn.Database := TSQLiteDBRec(s).FileName;
      conn.Password := TSQLiteDBRec(s).Pwd;
      try
        try
          Conn.Open;
        except
          MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
          DatabaseList.Delete(DatabaseList.IndexOf(s));
          Result := False;
          Exit;
        end;
        self.Caption   := Self.Caption + ' - ' + GetDatabaseName(FDatabaseFile);
        spStat.Caption := Format(siLang.GetText('sFmtConnected'),
          [GetDatabaseName(FDatabaseFile)]);
        DatabaseFile := TSQLiteDBRec(s).FileName;
        cbDBName.Items.Add(GetDatabaseName(TSQLiteDBRec(s).FileName));
      except
        on E: Exception do
        begin
          MessageBox(Handle, PChar(siLang.GetText('sReason') + E.Message),
            PChar(siLang.GetText('sHint')), MB_OK or MB_ICONERROR);
          Conn.Close;
          Result := False;
          DatabaseList.Delete(DatabaseList.IndexOf(s));
        end;
      end;
    end;
  end;
  BuildTree(EmptyStr);
end;

procedure TFormMain.OpenLastDB;
var
  dbname: string;
begin
  if DatabaseList.Count = 0 then
    Exit;
  dbname := TSQLiteDBRec(DatabaseList[DatabaseList.Count - 1]).FileName;
  Conn.Close;
  Conn.Database := dbname;
  Conn.Password := TSQLiteDBRec(DatabaseList[DatabaseList.Count - 1]).Pwd;
  try
    Conn.Open;
  except
    MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
    Exit;
  end;
end;

procedure TFormMain.ppMainChange(Sender: TObject);
var
  pg: TRzTabSheet;
  dbName: string;
  p1,p2: integer;
begin
  if ppMain.PageCount = 0 then
  begin
    miEdit.Visible     := True;
    Edit1.Visible      := False;
    Search1.Visible    := False;
    miSQL.Visible      := False;
    tbMain.Visible     := config.ViewToolbar;
    tbSQL.Visible      := False;
    spPOS.Caption      := EmptyStr;
    BtnRefresh.Visible := False;
    RzSpacer3.Visible  := False;
    Exit;
  end;  
  pg := ppMain.ActivePage;
  if pg.ClassName = 'TPageTableStructure' then
  begin
    miEdit.Visible     := True;
    Edit1.Visible      := False;
    Search1.Visible    := False;
    miSQL.Visible      := False;
    tbMain.Visible     := config.ViewToolbar;
    tbSQL.Visible      := False;
    spPOS.Caption      := EmptyStr;
    BtnRefresh.Visible := True;
    RzSpacer3.Visible  := True;
  end;
  if (pg.ClassName = 'TPageTableData') or (pg.ClassName = 'TPageWelcome') then
  begin
    miEdit.Visible     := True;
    Edit1.Visible      := False;
    Search1.Visible    := False;
    miSQL.Visible      := False;
    tbMain.Visible     := config.ViewToolbar;
    tbSQL.Visible      := False;
    spPOS.Caption      := EmptyStr;
    BtnRefresh.Visible := False;
    RzSpacer3.Visible  := False;
  end;
  if pg.ClassName = 'TPageSQLWindow' then
  begin
    // sql[123]
    // 12345678
    p1 := Pos('[',pg.Caption)+1;
    p2 := Pos(']',pg.Caption);
    dbName := Copy(pg.Caption,p1, p2-p1);
    cbDBName.ItemIndex := cbDBName.Items.IndexOf(dbName);
    cbDBNameChange(cbDBName);
    miEdit.Visible  := False;
    Edit1.Visible   := True;
    Search1.Visible := True;
    miSQL.Visible   := True;
    tbMain.Visible  := False;
    tbSQL.Visible   := config.ViewToolbar;
    if KeyComplete.InsertList.Count = 0 then
    begin
      KeyComplete.Editor := nil;
      FuncComplete.Editor := nil;
      TableComplete.Editor := nil;
      DataTypeComplete.Editor := nil;
    end
    else
    begin
      KeyComplete.Editor := TPageSQLWindow(pg).mmSQL;
      FuncComplete.Editor := TPageSQLWindow(pg).mmSQL;
      TableComplete.Editor := TPageSQLWindow(pg).mmSQL;
      DataTypeComplete.Editor := TPageSQLWindow(pg).mmSQL;
    end;
    
    ShowPOSInfo(
      TPageSQLWindow(pg).mmSQL.Lines.Count,
      TPageSQLWindow(pg).mmSQL.CaretX,
      TPageSQLWindow(pg).mmSQL.CaretY);
  end;
end;

procedure TFormMain.ppMainClose(Sender: TObject; var AllowClose: boolean);
var
  idx: integer;
begin
  if ppMain.PageCount = 0 then
    Exit;
  idx := ppMain.ActivePageIndex;
  ppMain.Pages[idx].Free;
  if ppMain.PageCount = 0 then
  begin
    miEdit.Visible     := True;
    Edit1.Visible      := False;
    Search1.Visible    := False;
    miSQL.Visible      := False;
    tbMain.Visible     := True;
    tbSQL.Visible      := False;
    spPOS.Caption      := EmptyStr;
    BtnRefresh.Visible := False;
    RzSpacer3.Visible  := False;
    Exit;
  end;

  if ppMain.PageCount > idx then
    ppMain.ActivePageIndex := idx
  else
    ppMain.ActivePageIndex := idx - 1;

end;

procedure TFormMain.sdSQLTypeChange(Sender: TObject);
begin
  case sdSQL.FilterIndex of
    1, 3:
    begin
      sdSQL.DefaultExt := 'sql';
    end;
    2:
    begin
      sdSQL.DefaultExt := 'txt';
    end;
  end;
end;

procedure TFormMain.SetDatabaseFile(const Value: string);
begin
  FDatabaseFile := Value;
  {$IFDEF TRIAL}
  self.Caption := 'SNDA SQLite Tool (Trial) - '+ GetDatabaseName(Value);;
  {$ELSE}
  self.Caption := 'SNDA SQLite Tool - '+ GetDatabaseName(Value);;
  {$ENDIF}
end;

procedure TFormMain.ShowInfo;
begin
  {$IFDEF TRIAL}
  self.Caption := 'SNDA SQLite Tool (Trial)';
  {$ELSE}
  self.Caption := 'SNDA SQLite Tool';
  {$ENDIF}
  spStat.Caption := siLang.GetText('sReady');
  if Conn.Connected then
  begin
    self.Caption   := Self.Caption + ' - ' + GetDatabaseName(DatabaseFile);
    spStat.Caption := Format(siLang.GetText('sFmtConnected'),
      [GetDatabaseName(DatabaseFile)]);
  end;
  if ppMain.PageCount > 0 then
  begin
    if ppMain.ActivePage.ClassName = 'TPageSQLWindow' then
      ShowPOSInfo(
        TPageSQLWindow(ppMain.ActivePage).mmSQL.Lines.Count,
        TPageSQLWindow(ppMain.ActivePage).mmSQL.CaretX,
        TPageSQLWindow(ppMain.ActivePage).mmSQL.CaretY
        )
    else
      spPOS.Caption := EmptyStr;
  end
  else
    spPOS.Caption := EmptyStr;
end;

procedure TFormMain.ShowPOSInfo(ACount, AX, AY: integer);
begin
  if not (ppMain.ActivePage.ClassName = 'TPageSQLWindow') then
    Exit;
  spPOS.Caption := Format(siLang.GetText('sFmtPOS'), [ACount, AY, AX]);
end;

procedure TFormMain.ShowTableStructure(APage: TPageTableStructure; ATableName: string);
var
  i:      integer;
  item:   TListItem;
  DBInfo: TList;
begin
  //  show table structure
  DBInfo := TList.Create;
  Conn.GetTableInfo(ATableName, DBInfo);
  APage.lvTable.Items.Clear;

  for i := 0 to DBInfo.Count - 1 do
  begin
    with TRaSQLiteField(DBInfo[i]) do
    begin
      item         := APage.lvTable.Items.Add;
      item.Caption := FieldName;
      item.SubItems.Add(FieldType);
      if FieldPK = 1 then
        item.SubItems.Add('PK')
      else
        item.SubItems.Add(EmptyStr);
      item.SubItems.Add(FieldDefault);
    end;
  end;

  DBInfo.Free;
end;

procedure TFormMain.ShowUnregForm;
begin
  // show unreg form
  with TFormUnregHint.Create(Application) do
  begin
    ShowModal;
    Free;
  end;  
end;

procedure TFormMain.StatusBar1Click(Sender: TObject);
begin
  //  view status bar
  Config.ViewStatusbar := not Config.ViewStatusbar;
  sbMain.Visible := Config.ViewStatusbar;
  StatusBar1.Checked := Config.ViewStatusbar;
end;

procedure TFormMain.TableCompleteExecute(Kind: SynCompletionType;
  Sender: TObject; var CurrentInput: string; var x, y: Integer;
  var CanExecute: Boolean);
var
  aliasName: string;
  realName:string;
  i: Integer;
  fn: string;
  xloop: Integer;
begin
  {$IFDEF TRIAL}
  CanExecute:=false;
  Exit;
  {$ENDIF}
  //  popup table field code complete
  // get alias table name before dot.
  aliasName := EmptyStr;
  for i := TableComplete.Editor.SelStart-1 downto 1 do
  begin
    if TableComplete.Editor.Lines.Text[i] in ['0'..'9','A'..'Z','a'..'z','_'] then
      aliasName := TableComplete.Editor.Lines.Text[i] + aliasName
    else
      Break;
  end;
 //  ShowMessage(aliasName);
  // get read table name of alias name
  TableComplete.ItemList.Clear;
  TableComplete.InsertList.Clear;

  with TSQLiteTableStruct.Create do
    begin
      Connection := Conn;
      TableName := aliasName;

      for xloop:=0 to FieldsList.Count -1  do
      // for fn in FieldsList do
      begin
        fn := FieldsList[xloop];
        TableComplete.InsertList.Add(fn);
        TableComplete.ItemList.Add('\color{clPurple}'+fn);
      end;
      Free;
    end;

  CanExecute := TableComplete.InsertList.Count > 0;
  if CanExecute then
    Exit;

  realName := GetRealTableNameWithAlias(aliasName, TableComplete.Editor.Lines.Text,TableComplete.Editor.SelStart);
  if realName = EmptyStr then
  begin
    CanExecute := False;
    Exit;
  end;

  with TSQLiteTableStruct.Create do
  begin
    Connection := Conn;
    TableName := realName;
    for xloop := 0 to FieldsList.Count - 1 do
    // for fn in FieldsList do
    begin
      fn := FieldsList[xloop];
      TableComplete.InsertList.Add(fn);
      TableComplete.ItemList.Add('\color{clPurple}'+fn);
    end;
    Free;
  end;
  CanExecute := TableComplete.InsertList.Count > 0;
end;

procedure TFormMain.tvDBClick(Sender: TObject);
var
  idx:    integer;
  dbName: string;
begin

  // lvTable.Items.Clear;
  Tbl.Close;
  Blob.DataField := EmptyStr;
  if tvDB.Selected = nil then
    Exit;
  if tvDB.Selected.Level = 0 then
  begin
    idx          := GetRootIndex(tvDB.Selected, tvDB);
    DatabaseFile := TSQLiteDBRec(DatabaseList[idx]).FileName;
    Conn.Close;
    Conn.Database := DatabaseFile;
    conn.Password := TSQLiteDBRec(DatabaseList[idx]).Pwd;
    try
      Conn.Open;
    except
      MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
      Exit;
    end;
    Exit;

  end;
  if tvDB.Selected.Parent = nil then
    Exit;

  dbName       := TSQLiteDBRec(DatabaseList[GetRootIndex(GetRootNode(tvDB.Selected, tvDB), tvDB)]).FileName;
  DatabaseFile := dbName;
  Conn.Close;
  Conn.Database := dbName;
  conn.Password := TSQLiteDBRec(DatabaseList[GetRootIndex(GetRootNode(tvDB.Selected, tvDB), tvDB)]).Pwd;
  try
    Conn.Open;
  except
    MessageBox(Handle,PChar(silang.GetText('sPasswordError')), PChar(siLang.GetText('sError')), MB_OK or MB_ICONERROR);
    Exit;
  end;

  DatabaseFile := dbName;
  
  if tvDB.Selected.Level in [2, 3] then
    Exit;
    
  Tbl.Close;
  Tbl.TableName := tvDB.Selected.Text;
  Tbl.Open;

end;

procedure TFormMain.tvDBMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: integer);
var
  p, p1: TPoint;
begin
  if Button <> mbRight then
    Exit;
  if tvDB.Selected = nil then
    Exit;
  p1.X := x;
  p1.Y := y;
  p    := tvDB.ClientToScreen(p1);
  case tvDB.Selected.Level of
    0: pmLV0.Popup(p.X, p.Y);
    1:
    begin
      // check table or not
      if tvDB.Selected.ImageIndex = 10 then
        pmLV1.Popup(p.X, p.Y)
      else
        pmView.Popup(p.X, p.Y);
    end;
    2:
    begin
      if tvdb.Selected.ImageIndex <> 63 then
        pmLV2.Popup(p.X, p.Y);
    end;
  end;
end;

procedure TFormMain.FormActivate(Sender: TObject);
begin
  CloseSplash;
end;

procedure TFormMain.N2221Click(Sender: TObject);
begin
  ShowSplash;
end;

end.
